package com.syh.jn.scm.service.impl.supplier.purchase;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.util.other.ExtStringUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.dubbo.config.annotation.Service;
import com.syh.core.ddd.event.annotation.DomainEventHandle;
import com.syh.core.ddd.infrastructure.repository.AggregateRepository;
import com.syh.core.ddd.service.AbstractServiceImpl;
import com.syh.jn.scm.domain.driver.entity.logistics.DriverLogisticsBill;
import com.syh.jn.scm.domain.driver.event.DriverLogisticsBillEvent;
import com.syh.jn.scm.domain.operation.entity.supplier.OperaSupplier;
import com.syh.jn.scm.domain.operation.event.supplier.OperaSupplierEvent;
import com.syh.jn.scm.domain.supplier.entity.finance.StatementAccountBill;
import com.syh.jn.scm.domain.supplier.entity.logistics.LogisticsBill;
import com.syh.jn.scm.domain.supplier.entity.purchase.PurchaseReturnOrder;
import com.syh.jn.scm.domain.supplier.entity.purchase.PurchaseReturnOrderItem;
import com.syh.jn.scm.domain.supplier.event.LogisticsBillEvent;
import com.syh.jn.scm.domain.supplier.event.PurchaseReturnOrderEvent;
import com.syh.jn.scm.domain.supplier.event.finance.BusinessAccountRecordEvent;
import com.syh.jn.scm.domain.supplier.event.finance.StatementAccountBillEvent;
import com.syh.jn.scm.domain.supplier.repository.logistics.LogisticsBillRepository;
import com.syh.jn.scm.domain.supplier.repository.purchase.PurchaseReturnOrderRepository;
import com.syh.jn.scm.dto.supplier.purchase.PurchaseReturnOrderItemVo;
import com.syh.jn.scm.dto.supplier.purchase.PurchaseReturnOrderMto;
import com.syh.jn.scm.dto.supplier.purchase.PurchaseReturnOrderSto;
import com.syh.jn.scm.dto.supplier.purchase.PurchaseReturnOrderVo;
import com.syh.jn.scm.dto.support.FilesDto;
import com.syh.jn.scm.service.api.supplier.finance.enums.StatementAccountBillEnum;
import com.syh.jn.scm.service.api.supplier.logistics.enums.LogisticsBillEnums;
import com.syh.jn.scm.service.api.supplier.purchase.PurchaseReturnOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
@Transactional
public class PurchaseReturnOrderServiceImpl extends AbstractServiceImpl<PurchaseReturnOrderSto, PurchaseReturnOrderMto, PurchaseReturnOrderVo, PurchaseReturnOrder, Long> implements PurchaseReturnOrderService {
  @Autowired
  private PurchaseReturnOrderRepository purchaseReturnOrderRepository;
  @Autowired
  private LogisticsBillRepository logisticsBillRepository;

  @Override
  protected AggregateRepository<PurchaseReturnOrder, Long> getAggregateRepository() {
    return purchaseReturnOrderRepository;
  }

  /**
   * 新增采购退货单
   *
   * @param sto
   * @return
   */
  @Override
  public Long save(PurchaseReturnOrderSto sto) {
    PurchaseReturnOrder order = new PurchaseReturnOrder(sto);
    Long orderId = purchaseReturnOrderRepository.add(order);
    this.publicEvent(PurchaseReturnOrderEvent.buildPurchaseReturnOrderCreated(new Object[]{order}));
    return orderId;
  }

  /**
   * 修改采购退货单
   *
   * @param mto
   */
  @Override
  public void update(PurchaseReturnOrderMto mto) {
    PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(mto.getId());
    PurchaseReturnOrder oldOrder = purchaseReturnOrderRepository.getById(mto.getId());
    order.modify(mto);//修改逻辑
    purchaseReturnOrderRepository.update(order);
    this.publicEvent(PurchaseReturnOrderEvent.buildPurchaseReturnOrderUpdated(new Object[]{order,oldOrder}));
  }

  /**
   * 根据id删除采购退货单
   *
   * @param id
   */
  @Override
  public void delete(Long id) {
    PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(id);
    order.destroy();//删除的逻辑
    purchaseReturnOrderRepository.remove(order);
  }

  /**
   * 根据id拿到订单明细
   *
   * @param id
   * @return
   */
  @Override
  public List<PurchaseReturnOrderItemVo> getItem(Long id) {
    PurchaseReturnOrder purchaseReturnOrder = purchaseReturnOrderRepository.getById(id);
    purchaseReturnOrder.check(purchaseReturnOrder);
    return this.transformPurchaseReturn(purchaseReturnOrderRepository.getItem(id));
  }

  /**
   * 根据采购退货订单id查出明细
   *
   * @param ids
   * @return
   */
  @Override
  public List<PurchaseReturnOrderItemVo> getItemsByPurchaseReturnOrderIds(Long[] ids) {
    return this.transformPurchaseReturn(purchaseReturnOrderRepository.getItemsByPurchaseReturnOrderIds(ids));
  }

  /**
   * 取消订单
   *
   * @param id
   */
  @Override
  public void cancel(Long id) {
    PurchaseReturnOrder purchaseReturnOrder = purchaseReturnOrderRepository.getById(id);
    purchaseReturnOrder.cancel();
    purchaseReturnOrderRepository.cancel(purchaseReturnOrder);
    this.publicEvent(PurchaseReturnOrderEvent.buildPurchaseReturnOrderCancel(new Object[]{purchaseReturnOrder}));
  }

  /**
   * 上传单据图片
   *
   * @param dto
   */
  @Override
  public void upload(FilesDto dto) {
    ExtAssert.notNull(dto.getId(), "id不能为空");
    PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(dto.getId());
    order.upload(dto);
    purchaseReturnOrderRepository.upload(order);
  }

  /**
   * 批量保存
   *
   * @param mapStoList
   * @return
   */
  @Override
  public List<Long> batchSaveWithVirtualId(List<Map<String, String>> mapStoList) {
    List<Long> ids = new ArrayList<>();
    PurchaseReturnOrderSto purchaseReturnOrderSto = new PurchaseReturnOrderSto();
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    Long inputTime = null;
    List<PurchaseReturnOrderSto> orderStoList = new ArrayList<>();
    for (Map<String, String> orderSto : mapStoList) {
      if (ExtStringUtils.isBlank(orderSto.get("goodsName")) && !ExtStringUtils.isBlank(orderSto.get("returnCode"))) {
        try {
          inputTime = simpleDateFormat.parse(orderSto.get("inputDateTimestamp")).getTime();
        } catch (ParseException e) {
          e.printStackTrace();
        }
        purchaseReturnOrderSto = PurchaseReturnOrderSto.builder()
                .returnCode(orderSto.get("returnCode"))
                .upStreamCompanyId(Long.valueOf(orderSto.get("upStreamCompanyId")))
                .businessEntityId(Long.valueOf(orderSto.get("businessEntityId")))
                .extCode(orderSto.get("returnCode"))
                .deliName(orderSto.get("deliName"))
                .deliTel(orderSto.get("deliTel"))
                .deliArea(orderSto.get("deliArea"))
                .inputDateTimestamp(inputTime)
                .deliAddress(orderSto.get("deliAddress"))
                .discount(BigDecimal.valueOf(Double.valueOf(orderSto.get("discount"))))
                .returnTotalAmount(BigDecimal.valueOf(Double.valueOf(orderSto.get("returnTotalAmount"))))
                .remark(orderSto.get("abstract")+orderSto.get("remark"))
                .build();
        orderStoList.add(purchaseReturnOrderSto);
      }
    }
    orderStoList.forEach(orderSto -> {
      Long realId = this.save(this.putItem(orderSto, mapStoList));
      ids.add(realId);
    });
    return ids;
  }

  /**
   * 确认订单
   *
   * @param id 订单id
   */
  @Override
  public void confirmOrder(Long id) {
    PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(id);
    order.confirm();
    purchaseReturnOrderRepository.confirmOrder(order);
  }

  public PurchaseReturnOrderSto putItem(PurchaseReturnOrderSto orderSto, List<Map<String, String>> mapStoList) {
    List<PurchaseReturnOrderSto.PurchaseReturnOrderItemSTO> itemSTOList = new ArrayList<>();
    for (Map<String, String> item : mapStoList) {
      if (!ExtStringUtils.isBlank(item.get("goodsName"))) {
        PurchaseReturnOrderSto.PurchaseReturnOrderItemSTO itemSto = orderSto.new PurchaseReturnOrderItemSTO();
        itemSto.setReturnCode(item.get("returnCode"));
        itemSto.setGoodsId(Long.valueOf(item.get("goodsId")));
        itemSto.setPrice(BigDecimal.valueOf(Double.valueOf(item.get("price"))));
        itemSto.setReturnQuantity(BigDecimal.valueOf(Double.valueOf(item.get("returnQuantity"))));
        itemSto.setReturnTotalAmount(BigDecimal.valueOf(Double.valueOf(item.get("returnTotalAmount"))));
        itemSto.setRemark(item.get("remark"));
        if (itemSto.getReturnCode().equals(orderSto.getReturnCode())) {
          itemSTOList.add(itemSto);
          orderSto.setItems(itemSTOList);
        }
      }
    }
    orderSto.setReturnCode(null);
    return orderSto;
  }

  /**
   * 消费者：监听物流单创建（记录生成物流商品数量）
   * @param bill
   */
  @DomainEventHandle(LogisticsBillEvent.LOGISTICS_BILL_CREATED)
  protected void handleLogisticsBillCreated(LogisticsBill bill) {
    if (LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus().equals(bill.getOrderType())) {
      PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(bill.getOrderId());
      order.countGeneratedQuantity(bill,1);
      purchaseReturnOrderRepository.updateOrderAndItems(order);
    }
  }

  /**
   * 消费者：监听物流单删除（记录生成物流商品数量）
   * @param bill
   */
  @DomainEventHandle(LogisticsBillEvent.LOGISTICS_BILL_DELETED)
  protected void handleLogisticsBillDeleted(LogisticsBill bill) {
    if (LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus().equals(bill.getOrderType())) {
      PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(bill.getOrderId());
      order.countGeneratedQuantity(bill,2);
      purchaseReturnOrderRepository.updateOrderAndItems(order);
    }
  }


  /**
   * 消费者：监听物流单发货事件（修改发货数量）
   * @param bill
   */
  @DomainEventHandle(BusinessAccountRecordEvent.BUSINESS_ACCOUNT_RECORD_CHECK_DISCOUNT_AFTER)
  protected void handleLogisticsBillDelivery(LogisticsBill bill) {
    if (LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus().equals(bill.getOrderType())) {
      PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(bill.getOrderId());
      order.delivery(bill);
      purchaseReturnOrderRepository.updateOrderAndItems(order);
    }
  }

  /**
   * 消费者：监听物流单取消发货事件（修改发货数量）
   * @param bill
   */
  @DomainEventHandle(BusinessAccountRecordEvent.BUSINESS_ACCOUNT_RECORD_CHECK_DISCOUNT_BEFORE)
  protected void handleLogisticsBillCanceled(LogisticsBill bill) {
    if (LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus().equals(bill.getOrderType())) {
      PurchaseReturnOrder order = purchaseReturnOrderRepository.getById(bill.getOrderId());
      order.cancelDelivery(bill);
      purchaseReturnOrderRepository.updateOrderAndItems(order);
    }
  }


  /**
   * 消费者：监听对账单（生成对账单状态和对账单号）
   *
   * @param bill
   */
  @DomainEventHandle(StatementAccountBillEvent.STATEMENT_BILL_ACCOUNT_CREATED)
  protected void handleStatementBillAccountCreated(StatementAccountBill bill) {
      bill.getStatementAccountBillItems().forEach(billItem -> {
        if (billItem.getSourceType().equals(StatementAccountBillEnum.SOURCE_PURCHASE_RETURN_ORD.getStatus())) {
          PurchaseReturnOrder purchaseReturnOrder = purchaseReturnOrderRepository.getById(billItem.getSourceId());
          purchaseReturnOrder.generating(bill.getId());
          purchaseReturnOrderRepository.upload(purchaseReturnOrder);
        }
      });
  }

  /**
   * 消费者：监听对账单（修改对账单状态）
   *
   * @param bill
   */
  @DomainEventHandle(StatementAccountBillEvent.STATEMENT_BILL_ACCOUNT_UPDATA)
  protected void handleStatementBillAccountUpdata(StatementAccountBill bill) {
    Wrapper wrapper = Wrapper.build();
    wrapper.append(Restrictions.eq("statementId", bill.getId()));
    List<PurchaseReturnOrder> purchaseReturnOrders = purchaseReturnOrderRepository.getList(wrapper);
    purchaseReturnOrders.forEach(purchaseReturnOrder -> {
      purchaseReturnOrder.cancelGenerating();
      purchaseReturnOrderRepository.upload(purchaseReturnOrder);
    });
    bill.getStatementAccountBillItems().forEach(billItem -> {
      if (billItem.getSourceType().equals(StatementAccountBillEnum.SOURCE_PURCHASE_RETURN_ORD.getStatus())) {
        PurchaseReturnOrder purchaseReturnOrder = purchaseReturnOrderRepository.getById(billItem.getSourceId());
        purchaseReturnOrder.generating(bill.getId());
        purchaseReturnOrderRepository.upload(purchaseReturnOrder);
      }
    });
  }

  /**
   * 消费者：监听对账单（删除对账单状态和对账单号）
   *
   * @param bill
   */
  @DomainEventHandle(StatementAccountBillEvent.STATEMENT_BILL_ACCOUNT_DESTROY)
  protected void handleStatementBillAccountDestroy(StatementAccountBill bill) {
    bill.getStatementAccountBillItems().forEach(billItem -> {
      if (billItem.getSourceType().equals(StatementAccountBillEnum.SOURCE_PURCHASE_RETURN_ORD.getStatus())) {
        PurchaseReturnOrder purchaseReturnOrder = purchaseReturnOrderRepository.getById(billItem.getSourceId());
        purchaseReturnOrder.cancelGenerating();
        purchaseReturnOrderRepository.upload(purchaseReturnOrder);
      }
    });
  }

  /**
   * 消费者：监听服务商反开账（删除所有该服务商的采购退货单）
   */
  @DomainEventHandle(OperaSupplierEvent.SUPPLIER_REVERSAL_ACCOUNT)
  protected void handleSupplierReversalAccount(OperaSupplier supplier) {
    this.purchaseReturnOrderRepository.deleteByBusinessEntityId(supplier.getId());
  }

  /**
   * 内部方法  业务模型转传输对象
   *
   * @param entityList
   * @return
   */
  private List<PurchaseReturnOrderItemVo> transformPurchaseReturn(List<PurchaseReturnOrderItem> entityList) {
    List<PurchaseReturnOrderItemVo> voList = new ArrayList<>();
    entityList.stream().forEach((entity) -> {
      PurchaseReturnOrderItemVo vo = new PurchaseReturnOrderItemVo();
      ExtBeanUtils.copyProperties(entity, vo);
      voList.add(vo);
    });
    return voList;
  }
}
